#pragma once
/*
    日志器模块:
    1.抽象日志器基类
    2.派生出子类(同步,异步)
*/

#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>
#include <unordered_map>

namespace jiuqilog
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;

        Logger(const std::string &logger_name,
               LogLevel::value limit_level,
               Formatter::ptr &formatter,
               std::vector<LogSink::ptr> &sinks)
            : _logger_name(logger_name),
              _limit_level(limit_level),
              _formatter(formatter),
              _sinks(sinks.begin(), sinks.end())
        {
        }

        std::string name() { return _logger_name; }

        void debug(const std::string &file, const size_t &line, const std::string fmt, ...)
        {
            // 判断当前日志是否达到了输出等级
            if (LogLevel::value::DEBUG < _limit_level)
                return;
            // 对数据进行格式化,得到日志消息字符串
            char *res;
            va_list vl;
            va_start(vl, fmt);
            int len = vasprintf(&res, fmt.c_str(), vl);
            va_end(vl);
            if (len == -1)
            {
                std::cerr << "vasprintf error!" << std::endl;
                return;
            }
            serialize(LogLevel::value::DEBUG, file, line, res);
            free(res);
        }
        void info(const std::string &file, const size_t &line, const std::string fmt, ...)
        {
            // 判断当前日志是否达到了输出等级
            if (LogLevel::value::INFO < _limit_level)
                return;
            // 对数据进行格式化,得到日志消息字符串
            char *res;
            va_list vl;
            va_start(vl, fmt);
            int len = vasprintf(&res, fmt.c_str(), vl);
            va_end(vl);
            if (len == -1)
            {
                std::cerr << "vasprintf error!" << std::endl;
                return;
            }
            serialize(LogLevel::value::INFO, file, line, res);
            free(res);
        }
        void warn(const std::string &file, const size_t &line, const std::string fmt, ...)
        {
            // 判断当前日志是否达到了输出等级
            if (LogLevel::value::WARN < _limit_level)
                return;
            // 对数据进行格式化,得到日志消息字符串
            char *res;
            va_list vl;
            va_start(vl, fmt);
            int len = vasprintf(&res, fmt.c_str(), vl);
            va_end(vl);
            if (len == -1)
            {
                std::cerr << "vasprintf error!" << std::endl;
                return;
            }
            serialize(LogLevel::value::WARN, file, line, res);
            free(res);
        }
        void error(const std::string &file, const size_t &line, const std::string fmt, ...)
        {
            // 判断当前日志是否达到了输出等级
            if (LogLevel::value::ERROR < _limit_level)
                return;
            // 对数据进行格式化,得到日志消息字符串
            char *res;
            va_list vl;
            va_start(vl, fmt);
            int len = vasprintf(&res, fmt.c_str(), vl);
            va_end(vl);
            if (len == -1)
            {
                std::cerr << "vasprintf error!" << std::endl;
                return;
            }
            serialize(LogLevel::value::ERROR, file, line, res);
            free(res);
        }
        void fatal(const std::string &file, const size_t &line, const std::string fmt, ...)
        {
            // 判断当前日志是否达到了输出等级
            if (LogLevel::value::FATAL < _limit_level)
                return;
            // 对数据进行格式化,得到日志消息字符串
            char *res;
            va_list vl;
            va_start(vl, fmt);
            int len = vasprintf(&res, fmt.c_str(), vl);
            va_end(vl);
            if (len == -1)
            {
                std::cerr << "vasprintf error!" << std::endl;
                return;
            }
            serialize(LogLevel::value::FATAL, file, line, res);
            free(res);
        }

    protected:
        void serialize(LogLevel::value level, const std::string &file, const size_t &line, char *str)
        {
            // 构造LogMsg
            LogMsg msg(level, line, file, _logger_name, str);
            // 格式化LogMsg
            std::string message = _formatter->format(msg);
            // 日志落地
            log(message.c_str(), message.size());
        }
        virtual void log(const char *data, size_t len) = 0;

    protected:
        std::mutex _mutex;
        std::string _logger_name;
        std::atomic<LogLevel::value> _limit_level;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };

    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name,
                   LogLevel::value limit_level,
                   Formatter::ptr &formatter,
                   std::vector<LogSink::ptr> &sinks)
            : Logger(logger_name, limit_level, formatter, sinks)
        {
        }

    protected:
        void log(const char *data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mutex);
            for (auto &sink : _sinks)
            {
                sink->log(data, len);
            }
        }
    };

    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &logger_name,
                    LogLevel::value limit_level,
                    Formatter::ptr &formatter,
                    std::vector<LogSink::ptr> &sinks,
                    AsyncType looper_type = AsyncType::ASYNC_SAFE)
            : Logger(logger_name, limit_level, formatter, sinks),
              _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), looper_type))
        // realLog第一个参数默认为this,所以我们要将this绑定到回调函数中,以符合回调函数的参数需求
        {
        }

        void realLog(Buffer &buffer) // 实际完成日志落地的函数,也是异步线程的回调函数
        {
            for (auto &sink : _sinks)
            {
                sink->log(buffer.begin(), buffer.readAbleSize());
            }
        }

    private:
        AsyncLooper::ptr _looper;

    protected:
        void log(const char *data, size_t len) override
        {
            // 将日志信息输入到缓冲区中
            _looper->push(data, len);
        }
    };

    enum class LoggerType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };
    // 使用建造者模式建造日志器
    class LoggerBuilder
    {
    public:
        LoggerBuilder() : _logger_type(LoggerType::LOGGER_SYNC),
                          _limit_level(LogLevel::value::DEBUG),
                          _async_type(AsyncType::ASYNC_SAFE)
        {
        }
        void buildeEnableUnsafeAsync() { _async_type = AsyncType::ASYNC_UNSAFE; }
        void buildLoggerType(LoggerType type) { _logger_type = type; }
        void buildLoggerName(const std::string &name) { _logger_name = name; }
        void buildLoggerLevel(LogLevel::value level) { _limit_level = level; }
        void buildLoggerFormatter(const std::string &pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }
        template <class SinkType, class... Args>
        void buildLoggerSink(Args &&...args)
        {
            // LogSink::ptr sink = std::make_shared<SinkType>(std::forward<Args>(args)...);
            LogSink::ptr sink = SinkFactory::createSink<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(sink);
        }
        virtual Logger::ptr build() = 0;

    protected:
        AsyncType _async_type;
        LoggerType _logger_type;
        std::string _logger_name;
        std::atomic<LogLevel::value> _limit_level;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };

    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if (_formatter == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                _sinks.push_back(std::make_shared<StdoutSink>());
            }
            if (_logger_type == LoggerType::LOGGER_ASYNC)
            {
                return std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _async_type);
            }
            return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
        }
    };

    // 日志器管理模块
    class LoggerManager
    {
    public:
        LoggerManager(const LoggerManager &) = delete;
        LoggerManager &operator=(const LoggerManager &) = delete;

        // 单例模式
        static LoggerManager &getInstance()
        {
            static LoggerManager eton;
            return eton;
        }

        // 添加一个日志器
        void addLogger(Logger::ptr &logger)
        {
            if (hasLogger(logger->name()))
                return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(), logger));
        }

        // 判断日志器是否存在
        bool hasLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
                return false;
            return true;
        }

        // 获取一个日志器
        Logger::ptr getLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
                return _root_logger;
            return it->second;
        }

        // 获取默认日志器
        Logger::ptr rootLogger()
        {
            return _root_logger;
        }

    private:
        std::unordered_map<std::string, Logger::ptr> _loggers;
        std::mutex _mutex;
        Logger::ptr _root_logger; // 默认日志器

    private:
        LoggerManager()
        {
            std::unique_ptr<LoggerBuilder> builder = std::make_unique<LocalLoggerBuilder>();
            builder->buildLoggerName("root");
            _root_logger = builder->build();
            _loggers.insert(std::make_pair("root", _root_logger));
        }
    };

    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if (_formatter == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                _sinks.push_back(std::make_shared<StdoutSink>());
            }

            Logger::ptr logger;

            if (_logger_type == LoggerType::LOGGER_ASYNC)
            {
                logger = std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _async_type);
            }
            else
            {
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
            LoggerManager::getInstance().addLogger(logger);
            return logger;
        }
    };
}